Engine.Shader = function(){
    //default value
    this.ks = {
        r: 0.3,
        g: 0.3,
        b: 0.3
    };

    this.ka = {
        r: 0.1,
        g: 0.1,
        b: 0.1
    };

    this.kd = {
        r: 0.7,
        g: 0.7,
        b: 0.7
    };
    this.s = 32;
}

Engine.Shader.prototype = (function() {
    var convert = function(color){
        var max = Engine.MaxColor;
        var result = {
            r: Math.floor(color.r * max),
            g: Math.floor(color.g * max),
            b: Math.floor(color.b * max)
        };

        result.r = result.r > max ? max: result.r;
        result.g = result.g > max ? max: result.g;
        result.b = result.b > max ? max: result.b;
        return result;
    };
    
    var phong = function(ka, kd, ks, s, vertex, normal, lights)
    {
        var P = vertex.normalize();
        var N = normal.normalize();
        var E = new Engine.Vector3(0, 0, -1);

        var color = {
            r: 0,
            g: 0,
            b: 0
        };

        for (var index in lights)
        {
            if (lights[index].type == Engine.LightType.Ambient)
            {
                color.r += ka.r * lights[index].color.r;
                color.g += ka.g * lights[index].color.g;
                color.b += ka.b * lights[index].color.b;
            }

            else if (lights[index].type == Engine.LightType.Directional)
            {
                var L = lights[index].direction;
                var NL = N.dot(L);
                var temp = N.dot(E);
                if (NL < 0 && temp < 0)
                {
                    N = new Engine.Vector3( - N.x, -N.y, -N.z)
                    NL = -NL;
                }
                else if ((temp > 0 && NL < 0) || (temp < 0 && NL > 0))
                {
                    continue;
                }

                var R = new Engine.Vector3(2 * NL * N.x - L.x, 2 * NL * N.y - L.y, 2 * NL * N.z - L.z);
                R = R.normalize();

                var RE = R.dot(E);
                if (RE > 0) {
                    RE = Math.pow(RE, s);
                    color.r += ks.r * lights[index].color.r * RE;
                    color.g += ks.g * lights[index].color.g * RE;
                    color.b += ks.b * lights[index].color.b * RE;
                }

                color.r += kd.r * lights[index].color.r * NL;
                color.g += kd.g * lights[index].color.g * NL;
                color.b += kd.b * lights[index].color.b * NL;
            }
        }
		
	
        return convert(color);
    };
	
	var hatching = function(ka, kd, ks, s, vertex, normal, lights,uv)
    {
        
		var P = vertex.normalize();
        var N = normal.normalize();
        var E = new Engine.Vector3(0, 0, -1);

        var color = {
            r: 0,
            g: 0,
            b: 0
        };

        for (var index in lights)
        {
            if (lights[index].type == Engine.LightType.Ambient)
            {
                color.r += ka.r * lights[index].color.r;
                color.g += ka.g * lights[index].color.g;
                color.b += ka.b * lights[index].color.b;
            }

            else if (lights[index].type == Engine.LightType.Directional)
            {
                var L = lights[index].direction;
                var NL = N.dot(L);
                var temp = N.dot(E);
                if (NL < 0 && temp < 0)
                {
                    N = new Engine.Vector3( - N.x, -N.y, -N.z)
                    NL = -NL;
                }
                else if ((temp > 0 && NL < 0) || (temp < 0 && NL > 0))
                {
                    continue;
                }

                var R = new Engine.Vector3(2 * NL * N.x - L.x, 2 * NL * N.y - L.y, 2 * NL * N.z - L.z);
                R = R.normalize();

                var RE = R.dot(E);
                if (RE > 0) {
                    RE = Math.pow(RE, s);
                    color.r += ks.r * lights[index].color.r * RE;
                    color.g += ks.g * lights[index].color.g * RE;
                    color.b += ks.b * lights[index].color.b * RE;
                }

                color.r += kd.r * lights[index].color.r * NL;
                color.g += kd.g * lights[index].color.g * NL;
                color.b += kd.b * lights[index].color.b * NL;
            }

        }


		var cValue = (0.21*color.r + 0.71*color.g + 0.08*color.b) *10;
	
		
		var c = [];
		c[0] = 0;
		c[1] = 0;
		c[2] = 0;
		c[3] = 0;
		c[4] = 0;
		c[5] = 0;
		
		if(cValue > 5)
		{
			c[5]=1.0;
		}else if(cValue>4.5)
		{
			c[5]=1.0 - (5-cValue)*2
			c[4]=1.0 - c[5];
		}else if(cValue>4)
		{
			c[4]=1.0 - (4.5-cValue)*2
			c[3]=1.0 - c[4];
		}else if(cValue>3.5)
		{
			c[3]=1.0 - (4-cValue)*2
			c[2]=1.0 - c[3];
		}else if(cValue>3)
		{
			c[2]=1.0 - (3.5-cValue)*2
			c[1]=1.0 - c[2];
		}else if (cValue>2.5)
		{
			c[1]=1.0 - (3-cValue)*2
			c[0]=1.0 - c[1];
		}else
		{
			c[0]=1.0;
		}
		
		if(this.texture)
		{
			color = this.texture.hatchColor(uv,c);
		}
		
        return convert(color);
		
		
    };
	
	
    /*
    var cubeUV = function(x,y,uv){
        var row = 3;
        var col = 3;
        if( x >= col || y >= row){
            console.log("bug");
            return uv;
        }
        else{
            return {
                u: (x+uv.u) * (1/col),
                v: (y+uv.v) * (1/row)
            };
        }
    };
    
    var reflectionFixed = function(ka, kd, ks, s, vertex, normal, ouv, lights, cp , texture)
    {
		var N = normal.normalize();
		var E = cp.minus(vertex);//cp is in wolrd space... so this is wrong
		E = E.normalize();
		var A = 2*E.dot(N); 
		var Temp = N.multiply(2*E.dot(N))
		var R = Temp.minus(E);		
		var maxComp = Math.max(Math.abs(R.x),Math.abs(R.y),Math.abs(R.z));
		R = R.divide(maxComp);

		var uv = {
			u:0,
			v:0
		};

		if(R.x == 1)
		{
			uv.u = 1 - (R.z + 1)/2;
			uv.v = (R.y + 1)/2;
			uv = cubeUV(2,1,uv);
			//right
		}
		else if(R.x == -1)
		{
			uv.u = (R.z + 1)/2;
			uv.v = (R.y + 1)/2;
			uv = cubeUV(0,1,uv);
			//left
		}
		else if(R.y == 1)
		{
			uv.u = (R.x + 1)/2;
			uv.v = 1 - (R.z + 1)/2;
			uv = cubeUV(1,2,uv);
			//top
		}
		else if(R.y == -1)
		{
			uv.u = (R.x + 1)/2;
			uv.v = (R.z + 1)/2;
			uv = cubeUV(1,0,uv);
			//bottom
		}
		else if(R.z == 1)
		{
			uv.u = 1 - (R.x + 1)/2;
			uv.v = 1 - (R.y + 1)/2;
			uv = cubeUV(1,1,uv);
			//front
	
		}
		else if(R.z == -1)
		{
			uv.u = 1-(R.x + 1)/2;
			uv.v = (R.y + 1)/2;
            uv = cubeUV(2,2,uv);
			//back
			
		}else
		{
			console.log(R.x + "," + R.y+ "," + R.z );	
		}
		
		var color = texture.color(uv);
		return phong(color,kd ,ks, s, vertex, normal, lights);
    };*/

    return {
        color: function(vertex, normal, uv, scene) {
            if(this.type == Engine.Reflection){
                return this.reflection(vertex, normal, uv,scene);
            }
            else if (this.type == Engine.Skybox && this.texture)
            {
                var color = this.texture.color(uv);
                return convert(color);
            }
            else if(this.type == Engine.Bump && this.texture){
                
                var u1 = this.texture.color({u:uv.u-0.005, v:uv.v}).r ;
                var u2 = this.texture.color({u:uv.u+0.005, v:uv.v}).r ;
                var bu = (u2 - u1) * 2;
                
                var v1 = this.texture.color({u:uv.u, v:uv.v-0.005}).r ;
                var v2 = this.texture.color({u:uv.u, v:uv.v+0.005}).r ;
                var bv = (v2 - v1) * 2;
                
                if(bu == 0 && bv == 0)
                    return phong(this.ka, this.kd, this.ks, this.s, vertex, normal, scene.lights);
                normal = normal.normalize();
                var pu = scene.camera.worldup.cross(normal).normalize();
                var pv = normal.cross(pu);
                
                var n1 = normal.multiply(bu).plus(pu).normalize();
                var n2 = normal.multiply(bv).plus(pv).normalize();
                var newNormal = n1.cross(n2);
                return phong(this.ka, this.kd, this.ks, this.s,vertex, newNormal, scene.lights);
            }
			else if(this.type == Engine.Hatching)
			{
                return hatching(this.ka, this.kd, this.ks, this.s, vertex, normal, scene.lights,uv);
			}
            else
            {
                if(this.texture){
                    var color = this.texture.color(uv);
                    return phong(color, color, this.ks, this.s, vertex, normal, scene.lights);
                }
                else{
                    return phong(this.ka, this.kd, this.ks, this.s, vertex, normal, scene.lights);
                }
            }
        },
		
        reflection : function(vertex, normal, ouv, scene){
            var N = normal.normalize();
    		var E = vertex.multiply(-1);
    		E = E.normalize();
    		var A = 2*E.dot(N); 
    		var Temp = N.multiply(2*E.dot(N))
    		var R = Temp.minus(E);		
    		var maxComp = Math.max(Math.abs(R.x),Math.abs(R.y),Math.abs(R.z));
    		R = R.divide(maxComp);

    		var uv = {
    			u:0,
    			v:0
    		};

    		var color;
    		if(R.x == 1)
    		{
    			uv.u = 1 - (R.z + 1)/2;
    			uv.v = (R.y + 1)/2;
    			color = this.cubeTexture["right"].color(uv);
    		}
    		else if(R.x == -1)
    		{
    			uv.u = (R.z + 1)/2;
    			uv.v = (R.y + 1)/2;
    			color = this.cubeTexture["left"].color(uv);
    		}
    		else if(R.y == 1)
    		{
    			uv.u = (R.x + 1)/2;
    			uv.v = 1 - (R.z + 1)/2;
    			color = this.cubeTexture["top"].color(uv);
    		}
    		else if(R.y == -1)
    		{
    			uv.u = (R.x + 1)/2;
    			uv.v = (R.z + 1)/2;
    			color = this.cubeTexture["bottom"].color(uv);
    		}
    		else if(R.z == 1)
    		{
    			uv.u = (R.x + 1)/2;
    			uv.v = (R.y + 1)/2;
    			color = this.cubeTexture["front"].color(uv);

    		}
    		else if(R.z == -1)
    		{
    			uv.u = 1- (R.x + 1)/2;
    			uv.v = (R.y + 1)/2;
                color = this.cubeTexture["back"].color(uv);

    		}else
    		{
    			console.log(R.x + "," + R.y+ "," + R.z);	
    		}
    		
            color = {
                r : color.r/ Engine.MaxColor,
                g : color.g/ Engine.MaxColor,
                b : color.b/ Engine.MaxColor
            };
    		//try to change those parameters
    		 
    		return phong(color, color, this.ks, this.s, vertex, normal, scene.lights);
        }
		
		
    };
})();
